A walkthrough of Ernest (2005)’s original analytical approach, from close reading of the paper.
Questions
- Is energy use across body size categories (regardless of species) uniform or multimodal?
- uniform would correspond generally to energetic equivalence/Damuth’s rule.
- multimodal might suggest different resource availability for different body sizes.
- If energy use is not uniform across body size categories, does the species level body size distribution correspond to modes of energy use?
- i.e. are there more species with mean body sizes around the modes of the body size-energy use distribution?
- if so, maybe it’s good to be certain sizes, and species accumulate at those optima.
Data
Ernest data
Ernest drew data from the Andrews LTER, the Sevilleta, Niwot Ridge, and Portal.
The data available online do not quite match the descriptive statistics reported in Ernest (2005).
Translation to replicate-becs
Download raw data. By default data will be stored in subdirectories of replicate-becs/data/paper/raw/ for each site.
download_raw_paper_data()
Process raw data into the appropriate format. This is a data table with a record for each individual and columns for species and weight in grams. By default these tables will be stored in subdirectores of replicate-becs/data/paper/processed.
process_raw_data()
Loading in data version 1.106.0
Load data tables for each community. There should be 9 communities.
communities <- load_paper_data()
length(communities)
[1] 9
Each community should be a data table with columns for species and size for each individual, for example:
names(communities)
[1] "andrews" "niwot" "portal" "sev-5pgrass" "sev-5plarrea"
[6] "sev-goatdraw" "sev-rsgrass" "sev-rslarrea" "sev-two22"
head(communities[[1]])
Constructing distributions/metrics
Body size-energy use distributions (BSED)
Ernest method
- Per individual, calculate metabolic rate as metabolic rate \(B \propto M^\frac{3}{4}\) where \(M\) is mass in grams.
- Sum energy use of all individuals in body size classes of .2 natural log units.
- Also try classes of .1 and .3 natural log units
- Convert raw energy use values for each body size class into the proportion of all the energy used in that community used by that body size class. This allows for comparisons between communities.
Translation to replicate-becs
For every individual, calculate metabolic rate and assign to a size class.
communities_energy <- lapply(communities, FUN = make_community_table, ln_units = 0.2)
head(communities_energy[[1]])
For each community, sum total energy use for each size class, and convert to the proportion of total energy use for that community.
bseds <- lapply(communities_energy, FUN = make_bsed)
head(bseds[[1]])

Species-level body size distributions (BSD)
Ernest method
- Frequency distributions of mean mass of each species in a community.
- For plotting (but not statistics), smoothed using kernel density estimation.
- Gaussian kernel to mimic the actual body size distribution in log space
- avg. std dev of the mean of the logged masses = smoothing parameter \(h\)
- align sampling points with the midpoint of each size class in the BSED
- after Manly 1996, “Are there clumps in body-size distributions?”, Ecology
Translation to replicate-becs
Calculate mean mass of each species in each community.
bsds <- lapply(communities, FUN = make_bsd)
head(bsds[[1]])

Energetic dominance (\(D_E\))
- Define “energy use modes” as contiguous body size classes where the energy use of each size class > 5% of the community total.
- i.e. a little bit more than the expectation if energy use is uniform across all body sizes
- RMD is unsure of this. Doesn’t the uniform expectation depend on the number of size classes?
- Calculate the total energy use for each species in the mode.
- Calculate the “dominance” of the species with the highest energy use in that mode as \(D_E = p_{max}\), where \(p_max\) is the maximum proportion of energy use by any one species in a mode.
- “a modification of the Berger-Parker dominance index (Berger and Parker 1970)”
Translation to replicate-becs
- Find contiguous size classes where each class has >5% of total energy use
- Calculate the total energy use for each species, and the proportion held by the species with the highest energy use (\(p_{max}\))
- Return \(p_{max}\) for every mode, along with the min and max size classes in that mode for each community
energetic_dom <- lapply(communities_energy, FUN = energetic_dominance)
head(energetic_dom[[1]])
- To plot, combine all modes from all communities and plot a histogram of \(D_E\) values.

- Out of curiousity, what happens if we define the modes with the cutoff proportional to the number of size classes (instead of a fixed 5%?)
energetic_dom_prop <- lapply(communities_energy, FUN = energetic_dominance, mode_cutoff = 'prop')

Statistical tests
Compare BSEDs among communities
Ernest approach
- For every pair of communities, create a pool of masses of all individuals from both communities.
- Draw two new communities with the same number of individuals as the empirical communities, pulling masses at random from the pool, with replacement.
- Calculate the DOI for the BSEDs of the two sample communities.
- Repeat 10000 for each pair.
- The P value is the proportion of sample DOIs greater (i.e. less overlap) than the empirical value.
Translation to replicate-becs
- For every pair of communities, pool all the masses
- Resample two communities of the right sizes
- Construct BSEDs for both communities
- Calculate the DOI of the two BSEDs
- Repeat 10000x
community_combination_indices = utils::combn(x = c(1:9), m = 2, simplify = TRUE) %>%
t() %>%
as.data.frame() %>%
dplyr::rename(community_a = V1, community_b = V2)
combine_communities = function(indices, communities) {
community_combination = list(community_a = communities[[indices[1]]], community_b = communities[[indices[2]]], community_names = c(names(communities)[[indices[1]]], names(communities)[[indices[2]]]))
return(community_combination)
}
community_combinations = apply(community_combination_indices, MARGIN = 1, FUN = combine_communities, communities = communities)
bsed_crosscomm_bootstraps = lapply(community_combinations, FUN = community_bootstrap,
bootstrap_function = 'bootstrap_crosscomm_bseds', nbootstraps = 10)


See histogram of p values for comparisons to see if commuities’ BSEDs are the same or different.
LS0tCnRpdGxlOiAiTmFycmF0aXZlIG9mIG9yaWdpbmFsIGFuYWx5c2lzIgphdXRob3I6ICJSZW5hdGEgRGlheiIKZGF0ZTogIjUvMTQvMjAxOSIKb3V0cHV0OiBodG1sX25vdGVib29rCi0tLQoKYGBge3Igc2V0dXAsIGluY2x1ZGUgPSBGfQpsaWJyYXJ5KHJlcGxpY2F0ZWJlY3MpCmRvd25sb2FkX2RhdGEgPSBGQUxTRQpgYGAKCkEgd2Fsa3Rocm91Z2ggb2YgRXJuZXN0ICgyMDA1KSdzIG9yaWdpbmFsIGFuYWx5dGljYWwgYXBwcm9hY2gsIGZyb20gY2xvc2UgcmVhZGluZyBvZiB0aGUgcGFwZXIuIAoKIyMgUXVlc3Rpb25zCgoxLiBJcyBlbmVyZ3kgdXNlIGFjcm9zcyBib2R5IHNpemUgY2F0ZWdvcmllcyAocmVnYXJkbGVzcyBvZiBzcGVjaWVzKSB1bmlmb3JtIG9yIG11bHRpbW9kYWw/CiAgLSB1bmlmb3JtIHdvdWxkIGNvcnJlc3BvbmQgZ2VuZXJhbGx5IHRvIGVuZXJnZXRpYyBlcXVpdmFsZW5jZS9EYW11dGgncyBydWxlLgogIC0gbXVsdGltb2RhbCBtaWdodCBzdWdnZXN0IGRpZmZlcmVudCByZXNvdXJjZSBhdmFpbGFiaWxpdHkgZm9yIGRpZmZlcmVudCBib2R5IHNpemVzLgoyLiBJZiBlbmVyZ3kgdXNlIGlzIG5vdCB1bmlmb3JtIGFjcm9zcyBib2R5IHNpemUgY2F0ZWdvcmllcywgZG9lcyB0aGUgc3BlY2llcyBsZXZlbCBib2R5IHNpemUgZGlzdHJpYnV0aW9uIGNvcnJlc3BvbmQgdG8gbW9kZXMgb2YgZW5lcmd5IHVzZT8KICAtIGkuZS4gYXJlIHRoZXJlIG1vcmUgc3BlY2llcyB3aXRoIG1lYW4gYm9keSBzaXplcyBhcm91bmQgdGhlIG1vZGVzIG9mIHRoZSBib2R5IHNpemUtZW5lcmd5IHVzZSBkaXN0cmlidXRpb24/CiAgLSBpZiBzbywgbWF5YmUgaXQncyBnb29kIHRvIGJlIGNlcnRhaW4gc2l6ZXMsIGFuZCBzcGVjaWVzIGFjY3VtdWxhdGUgYXQgdGhvc2Ugb3B0aW1hLgoKCiMjIERhdGEKCiMjIyMgRXJuZXN0IGRhdGEKRXJuZXN0IGRyZXcgZGF0YSBmcm9tIHRoZSBBbmRyZXdzIExURVIsIHRoZSBTZXZpbGxldGEsIE5pd290IFJpZGdlLCBhbmQgUG9ydGFsLiAKClRoZSBkYXRhIGF2YWlsYWJsZSBvbmxpbmUgZG8gbm90IHF1aXRlIG1hdGNoIHRoZSBkZXNjcmlwdGl2ZSBzdGF0aXN0aWNzIHJlcG9ydGVkIGluIEVybmVzdCAoMjAwNSkuIAoKIyMjIyBUcmFuc2xhdGlvbiB0byBgcmVwbGljYXRlLWJlY3NgCgpEb3dubG9hZCByYXcgZGF0YS4gQnkgZGVmYXVsdCBkYXRhIHdpbGwgYmUgc3RvcmVkIGluIHN1YmRpcmVjdG9yaWVzIG9mIGByZXBsaWNhdGUtYmVjcy9kYXRhL3BhcGVyL3Jhdy9gIGZvciBlYWNoIHNpdGUuIApgYGB7ciBkb3dubG9hZCBkYXRhIGlmIG5vdCBkb3dubG9hZGVkLCBpbmNsdWRlID0gRn0KaWYoZG93bmxvYWRfZGF0YSkgZG93bmxvYWRfcmF3X3BhcGVyX2RhdGEoKQpgYGAKCmBgYHtyIGRvd25sb2FkIHJhdyBkYXRhLCBldmFsID0gRn0KZG93bmxvYWRfcmF3X3BhcGVyX2RhdGEoKQpgYGAKClByb2Nlc3MgcmF3IGRhdGEgaW50byB0aGUgYXBwcm9wcmlhdGUgZm9ybWF0LiBUaGlzIGlzIGEgZGF0YSB0YWJsZSB3aXRoIGEgcmVjb3JkIGZvciBlYWNoIGluZGl2aWR1YWwgYW5kIGNvbHVtbnMgZm9yIGBzcGVjaWVzYCBhbmQgYHdlaWdodGAgaW4gZ3JhbXMuIEJ5IGRlZmF1bHQgdGhlc2UgdGFibGVzIHdpbGwgYmUgc3RvcmVkIGluIHN1YmRpcmVjdG9yZXMgb2YgYHJlcGxpY2F0ZS1iZWNzL2RhdGEvcGFwZXIvcHJvY2Vzc2VkYC4gCgpgYGB7ciBwcm9jZXNzIHBhcGVyIGRhdGF9CnByb2Nlc3NfcmF3X2RhdGEoKQpgYGAKCkxvYWQgZGF0YSB0YWJsZXMgZm9yIGVhY2ggY29tbXVuaXR5LiBUaGVyZSBzaG91bGQgYmUgOSBjb21tdW5pdGllcy4KCmBgYHtyIGxvYWQgY29tbXVuaXR5IGRhdGEsIGVjaG89VFJVRX0KY29tbXVuaXRpZXMgPC0gbG9hZF9wYXBlcl9kYXRhKCkKCmxlbmd0aChjb21tdW5pdGllcykKYGBgCgpFYWNoIGNvbW11bml0eSBzaG91bGQgYmUgYSBkYXRhIHRhYmxlIHdpdGggY29sdW1ucyBmb3Igc3BlY2llcyBhbmQgc2l6ZSBmb3IgZWFjaCBpbmRpdmlkdWFsLCBmb3IgZXhhbXBsZToKCmBgYHtyIGluc3BlY3QgY29tbXVuaXR5IGRhdGF9Cm5hbWVzKGNvbW11bml0aWVzKQpoZWFkKGNvbW11bml0aWVzW1sxXV0pCmBgYAoKCiMjIENvbnN0cnVjdGluZyBkaXN0cmlidXRpb25zL21ldHJpY3MKCiMjIyBCb2R5IHNpemUtZW5lcmd5IHVzZSBkaXN0cmlidXRpb25zIChCU0VEKQoKIyMjIyBFcm5lc3QgbWV0aG9kCgotIFBlciBpbmRpdmlkdWFsLCBjYWxjdWxhdGUgbWV0YWJvbGljIHJhdGUgYXMgbWV0YWJvbGljIHJhdGUgJEIgXHByb3B0byBNXlxmcmFjezN9ezR9JCB3aGVyZSAkTSQgaXMgbWFzcyBpbiBncmFtcy4KLSBTdW0gZW5lcmd5IHVzZSBvZiBhbGwgaW5kaXZpZHVhbHMgaW4gYm9keSBzaXplIGNsYXNzZXMgb2YgLjIgbmF0dXJhbCBsb2cgdW5pdHMuCiAgICAtIEFsc28gdHJ5IGNsYXNzZXMgb2YgLjEgYW5kIC4zIG5hdHVyYWwgbG9nIHVuaXRzCi0gQ29udmVydCByYXcgZW5lcmd5IHVzZSB2YWx1ZXMgZm9yIGVhY2ggYm9keSBzaXplIGNsYXNzIGludG8gdGhlIHByb3BvcnRpb24gb2YgYWxsIHRoZSBlbmVyZ3kgdXNlZCBpbiB0aGF0IGNvbW11bml0eSB1c2VkIGJ5IHRoYXQgYm9keSBzaXplIGNsYXNzLiBUaGlzIGFsbG93cyBmb3IgY29tcGFyaXNvbnMgYmV0d2VlbiBjb21tdW5pdGllcy4KCiMjIyMgVHJhbnNsYXRpb24gdG8gYHJlcGxpY2F0ZS1iZWNzYAoKRm9yIGV2ZXJ5IGluZGl2aWR1YWwsIGNhbGN1bGF0ZSBtZXRhYm9saWMgcmF0ZSBhbmQgYXNzaWduIHRvIGEgc2l6ZSBjbGFzcy4gCgpgYGB7ciBjb25zdHJ1Y3QgQlNFRHN9CmNvbW11bml0aWVzX2VuZXJneSA8LSBsYXBwbHkoY29tbXVuaXRpZXMsIEZVTiA9IG1ha2VfY29tbXVuaXR5X3RhYmxlLCBsbl91bml0cyA9IDAuMikKCmhlYWQoY29tbXVuaXRpZXNfZW5lcmd5W1sxXV0pCmBgYAoKRm9yIGVhY2ggY29tbXVuaXR5LCBzdW0gdG90YWwgZW5lcmd5IHVzZSBmb3IgZWFjaCBzaXplIGNsYXNzLCBhbmQgY29udmVydCB0byB0aGUgcHJvcG9ydGlvbiBvZiB0b3RhbCBlbmVyZ3kgdXNlIGZvciB0aGF0IGNvbW11bml0eS4KCmBgYHtyIG1ha2UgYnNlZHN9CmJzZWRzIDwtIGxhcHBseShjb21tdW5pdGllc19lbmVyZ3ksIEZVTiA9IG1ha2VfYnNlZCkKCmhlYWQoYnNlZHNbWzFdXSkKYGBgCgpgYGB7ciBwbG90IGJzZWRzLCBlY2hvPUZBTFNFLCBmaWcuaGVpZ2h0PTEwLCBmaWcud2lkdGg9MTB9Cgpic2Vkc19wbG90IDwtIHBsb3RfcGFwZXJfZGlzdHMoYnNlZHMsIGRpc3RfdHlwZSA9ICdic2VkJykKCmludmlzaWJsZShic2Vkc19wbG90KQpgYGAKCiMjIyBTcGVjaWVzLWxldmVsIGJvZHkgc2l6ZSBkaXN0cmlidXRpb25zIChCU0QpCgojIyMjIEVybmVzdCBtZXRob2QKLSBGcmVxdWVuY3kgZGlzdHJpYnV0aW9ucyBvZiBtZWFuIG1hc3Mgb2YgZWFjaCBzcGVjaWVzIGluIGEgY29tbXVuaXR5LgotIEZvciBwbG90dGluZyAoYnV0IG5vdCBzdGF0aXN0aWNzKSwgc21vb3RoZWQgdXNpbmcga2VybmVsIGRlbnNpdHkgZXN0aW1hdGlvbi4gCiAgICAtIEdhdXNzaWFuIGtlcm5lbCB0byBtaW1pYyB0aGUgYWN0dWFsIGJvZHkgc2l6ZSBkaXN0cmlidXRpb24gaW4gbG9nIHNwYWNlCiAgICAtIGF2Zy4gc3RkIGRldiBvZiB0aGUgbWVhbiBvZiB0aGUgbG9nZ2VkIG1hc3NlcyA9IHNtb290aGluZyBwYXJhbWV0ZXIgJGgkCiAgICAtIGFsaWduIHNhbXBsaW5nIHBvaW50cyB3aXRoIHRoZSBtaWRwb2ludCBvZiBlYWNoIHNpemUgY2xhc3MgaW4gdGhlIEJTRUQKICAgIC0gYWZ0ZXIgTWFubHkgMTk5NiwgIkFyZSB0aGVyZSBjbHVtcHMgaW4gYm9keS1zaXplIGRpc3RyaWJ1dGlvbnM/IiwgX0Vjb2xvZ3lfCiAgICAKIyMjIyBUcmFuc2xhdGlvbiB0byBgcmVwbGljYXRlLWJlY3NgCgpDYWxjdWxhdGUgbWVhbiBtYXNzIG9mIGVhY2ggc3BlY2llcyBpbiBlYWNoIGNvbW11bml0eS4gCgpgYGB7ciBjb25zdHJ1Y3QgYnNkc30gCgpic2RzIDwtIGxhcHBseShjb21tdW5pdGllcywgRlVOID0gbWFrZV9ic2QpIAoKaGVhZChic2RzW1sxXV0pCmBgYAoKYGBge3IgcGxvdCBic2RzLCBlY2hvPUZBTFNFLCBmaWcuaGVpZ2h0PTEwLCBmaWcud2lkdGg9MTB9Cgpic2RzX3Bsb3QgPC0gcGxvdF9wYXBlcl9kaXN0cyhic2RzLCBkaXN0X3R5cGUgPSAnYnNkJykKCmludmlzaWJsZShic2RzX3Bsb3QpCmBgYAoKCiMjIyBFbmVyZ2V0aWMgZG9taW5hbmNlICgkRF9FJCkKCi0gRGVmaW5lICJlbmVyZ3kgdXNlIG1vZGVzIiBhcyBjb250aWd1b3VzIGJvZHkgc2l6ZSBjbGFzc2VzIHdoZXJlIHRoZSBlbmVyZ3kgdXNlIG9mIGVhY2ggc2l6ZSBjbGFzcyA+IDUlIG9mIHRoZSBjb21tdW5pdHkgdG90YWwuIAogICAgLSBpLmUuIGEgbGl0dGxlIGJpdCBtb3JlIHRoYW4gdGhlIGV4cGVjdGF0aW9uIGlmIGVuZXJneSB1c2UgaXMgdW5pZm9ybSBhY3Jvc3MgYWxsIGJvZHkgc2l6ZXMKICAgIC0gUk1EIGlzIHVuc3VyZSBvZiB0aGlzLiBEb2Vzbid0IHRoZSB1bmlmb3JtIGV4cGVjdGF0aW9uIGRlcGVuZCBvbiB0aGUgbnVtYmVyIG9mIHNpemUgY2xhc3Nlcz8KLSBDYWxjdWxhdGUgdGhlIHRvdGFsIGVuZXJneSB1c2UgZm9yIGVhY2ggc3BlY2llcyBpbiB0aGUgbW9kZS4gCi0gQ2FsY3VsYXRlIHRoZSAiZG9taW5hbmNlIiBvZiB0aGUgc3BlY2llcyB3aXRoIHRoZSBoaWdoZXN0IGVuZXJneSB1c2UgaW4gdGhhdCBtb2RlIGFzICREX0UgPSBwX3ttYXh9JCwgd2hlcmUgJHBfbWF4JCBpcyB0aGUgbWF4aW11bSBwcm9wb3J0aW9uIG9mIGVuZXJneSB1c2UgYnkgYW55IG9uZSBzcGVjaWVzIGluIGEgbW9kZS4gCiAgICAtICJhIG1vZGlmaWNhdGlvbiBvZiB0aGUgQmVyZ2VyLVBhcmtlciBkb21pbmFuY2UgaW5kZXggKEJlcmdlciBhbmQgUGFya2VyIDE5NzApIgoKIyMjIyBUcmFuc2xhdGlvbiB0byBgcmVwbGljYXRlLWJlY3NgCgotIEZpbmQgY29udGlndW91cyBzaXplIGNsYXNzZXMgd2hlcmUgZWFjaCBjbGFzcyBoYXMgPjUlIG9mIHRvdGFsIGVuZXJneSB1c2UKLSBDYWxjdWxhdGUgdGhlIHRvdGFsIGVuZXJneSB1c2UgZm9yIGVhY2ggc3BlY2llcywgYW5kIHRoZSBwcm9wb3J0aW9uIGhlbGQgYnkgdGhlIHNwZWNpZXMgd2l0aCB0aGUgaGlnaGVzdCBlbmVyZ3kgdXNlICgkcF97bWF4fSQpCi0gUmV0dXJuICRwX3ttYXh9JCBmb3IgZXZlcnkgbW9kZSwgYWxvbmcgd2l0aCB0aGUgbWluIGFuZCBtYXggc2l6ZSBjbGFzc2VzIGluIHRoYXQgbW9kZSBmb3IgZWFjaCBjb21tdW5pdHkKCmBgYHtyIGVuZXJnZXRpYyBkb21pbmFuY2V9CgplbmVyZ2V0aWNfZG9tIDwtIGxhcHBseShjb21tdW5pdGllc19lbmVyZ3ksIEZVTiA9IGVuZXJnZXRpY19kb21pbmFuY2UpIAoKaGVhZChlbmVyZ2V0aWNfZG9tW1sxXV0pCgpgYGAKCi0gVG8gcGxvdCwgY29tYmluZSBhbGwgbW9kZXMgZnJvbSBhbGwgY29tbXVuaXRpZXMgYW5kIHBsb3QgYSBoaXN0b2dyYW0gb2YgJERfRSQgdmFsdWVzLgoKYGBge3IgcGxvdCBFZCwgZWNobz1GQUxTRSwgZmlnLmhlaWdodD01LCBmaWcud2lkdGg9NX0KZV9kb21fcGxvdCA8LSBwbG90X2VfZG9tKGVuZXJnZXRpY19kb20pCmVfZG9tX3Bsb3QKYGBgCgoKLSBPdXQgb2YgY3VyaW91c2l0eSwgd2hhdCBoYXBwZW5zIGlmIHdlIGRlZmluZSB0aGUgbW9kZXMgd2l0aCB0aGUgY3V0b2ZmIHByb3BvcnRpb25hbCB0byB0aGUgbnVtYmVyIG9mIHNpemUgY2xhc3NlcyAoaW5zdGVhZCBvZiBhIGZpeGVkIDUlPykKCmBgYHtyIGVkb20gcHJvcG9ydGlvbmFsfQplbmVyZ2V0aWNfZG9tX3Byb3AgPC0gbGFwcGx5KGNvbW11bml0aWVzX2VuZXJneSwgRlVOID0gZW5lcmdldGljX2RvbWluYW5jZSwgbW9kZV9jdXRvZmYgPSAncHJvcCcpIApgYGAKCmBgYHtyIHBsb3QgZWRvbSBwcm9wb3J0aW9uYWwsIGVjaG89RkFMU0UsIGZpZy5oZWlnaHQ9NSwgZmlnLndpZHRoPTV9CmVfZG9tX3Byb3BfcGxvdCA8LSBwbG90X2VfZG9tKGVuZXJnZXRpY19kb21fcHJvcCkKZV9kb21fcHJvcF9wbG90CmBgYAoKLSBSTUQ6IFRoZXkncmUgc2ltaWxhci4gCgojIyBTdGF0aXN0aWNhbCB0ZXN0cwoKIyMjIENvbXBhcmluZyBCU0VEcyB0byB1bmlmb3JtCgojIyMjIEVybmVzdCBhcHByb2FjaAoKLSBVc2UgYm9vdHN0cmFwIHNhbXBsaW5nIHRvIGNvbXBhcmUgdG8gdW5pZm9ybSBkaXN0cmlidXRpb25zLgotIEZvciBldmVyeSBjb21tdW5pdHksIGRyYXcgMTAwMDAgc2FtcGxlcyAoc2ltIGNvbW11bml0aWVzKToKICAgIC0gU2FtZSBudW1iZXIgb2YgaW5kaXZpZHVhbHMgYXMgdGhlIGVtcGlyaWNhbCBjb21tdW5pdHksIGRyYXduIGZyb20gYSB1bmlmb3JtIGRpc3RyaWJ1dGlvbiByYW5naW5nIGZyb20gdGhlIHNtYWxsZXN0IHRvIGxhcmdlc3Qgfn5ib2R5IHNpemV+fiBpbmRpdmlkdWFsIG1ldGFib2xpYyByYXRlIG9mIGFueSBpbmRpdmlkdWFsIGluIHRoYXQgY29tbXVuaXR5LgotIEZvciBzaW0gY29tbXVuaXRpZXMgYW5kIHRoZSBlbXBpcmljYWwgY29tbXVuaXR5LCBjYWxjdWxhdGUgYSBkaXN0cmlidXRpb24gb3ZlcmxhcCBpbmRleCAoJERPSSQpOgogICAgLSAkRE9JID0gXHN1bV9rIHt8eV97YWt9IC0geV97Ymt9fH0kIHdoZXJlICR5JCBpcyB0aGUgdmFsdWUgZm9yIHNpemUgY2xhc3MgJGskIGluIGNvbW11bml0aWVzICRhJCBhbmQgJGIkLgogICAgLSAkRE9JJCB2YWx1ZXMgd2lsbCByYW5nZSBmcm9tIDAgKGNvbXBsZXRlIG92ZXJsYXApIHRvIDIgKG5vIG92ZXJsYXApLiAKICAgIC0gRm9yIHRoZSBCU0VEIGJvb3RzdHJhcHMsIGNvbW11bml0eSAkYSQgaXMgdGhlIGVtcGlyaWNhbCBvciBzaW0gZGlzdHJpYnV0aW9uLCBhbmQgY29tbXVuaXR5ICRiJCBpcyBhIHRydWUgdW5pZm9ybSBkaXN0cmlidXRpb24gfn4oaS5lLiAkeV97Ymt9ID0gXGZyYWN7MX17XG1heChrKX0kIGZvciBhbGwgJGskKX5+CiAgICAgICAgLSAiVHJ1ZSB1bmlmb3JtIGRpc3RyaWJ1dGlvbiI6IFRoZXJlIGFyZSBleGFjdGx5IHRoZSBzYW1lIG51bWJlciBvZiBpbmRpdmlkdWFscyBvZiBldmVyeSBzaXplLiAKLSBDYWxjdWxhdGUgdGhlICRET0kkIGZvciBhbGwgc2ltIGNvbW11bml0aWVzIGFuZCB0aGUgZW1waXJpY2FsLgotIEZpbmQgdGhlIHF1YW50aWxlIHZhbHVlIGZvciB0aGUgZW1waXJpY2FsICRET0kkIGNvbXBhcmVkIHRvIHRoZSBkaXN0cmlidXRpb24gb2Ygc2ltICRET0kkcy4gVGhpcyBpcyB0aGUgcC12YWx1ZTsgaS5lLiB0aGUgcHJvcG9ydGlvbiBvZiBzaW0gdW5pZm9ybSBkaXN0cmlidXRpb25zIHdpdGggRE9JcyBncmVhdGVyIHRoYW4gdGhlIGVtcGlyaWNhbC4KCiMjIyMgVHJhbnNsYXRpb24gdG8gYHJlcGxpY2F0ZS1iZWNzYAoKLSBGb3IgYSBnaXZlbiBlbXBpcmljYWwgY29tbXVuaXR5LCBkcmF3IDEwMDAwIHNpbSBjb21tdW5pdGllcyBlYWNoIHdpdGggdGhlIHNhbWUgbnVtYmVyIG9mIGluZGl2aWR1YWxzICRuJCwgd2l0aCBib2R5IHNpemVzIHJhbmRvbWx5IGRyYXduIGZyb20gYSB1bmlmb3JtIGRpc3RyaWJ1dGlvbiBmcm9tIHRoZSBtaW5pbXVtIHRvIG1heGltdW0gYm9keSBzaXplIGluIHRoYXQgY29tbXVuaXR5LgotIENhbGN1bGF0ZSB0aGUgJERPSSQgb2YgZWFjaCBzaW0gY29tbXVuaXR5IGNvbXBhcmVkIHRvIGEgdHJ1ZSB1bmlmb3JtIGRpc3RyaWJ1dGlvbi4gCiAgICAtIFRydWUgdW5pZm9ybSBkaXN0cmlidXRpb24gPSBldmVyeSBzaXplIGZyb20gdGhlIG1pbmltdW0gdG8gdGhlIG1heGltdW0gc2l6ZSBpbiB0aGUgY29tbXVuaXR5IChieSAuMWcpIGhhcyBleGFjdGx5IG9uZSBpbmRpdmlkdWFsLgoKYGBge3IgQlNFRC11bmlmb3JtIGJvb3RzdHJhcHBlZCBET0lzfQoKYnNlZF91bmlmb3JtX2Jvb3RzdHJhcHMgPC0gbGFwcGx5KGNvbW11bml0aWVzLCBGVU4gPSBjb21tdW5pdHlfYm9vdHN0cmFwLCAgYm9vdHN0cmFwX2Z1bmN0aW9uID0gJ2Jvb3RzdHJhcF91bmlmX2JzZWRfZG9pJywgbmJvb3RzdHJhcHMgPSAxMCkKCmBgYAoKCl9TZWUgaXNzdWUgIzQgb24gZ2l0aHViLl8KICAgIAogICAgCmBgYHtyIHBsb3QgQlNFRC11bmlmb3JtIGJvb3RzdHJhcCBET0lzIHYgZW1waXJpY2FsLGVjaG89RkFMU0UsIGZpZy5oZWlnaHQ9MTAsIGZpZy53aWR0aD0xMH0gCgpic2VkX3VuaWZvcm1fYm9vdHN0cmFwX3Bsb3QgPC0gcGxvdF9wYXBlcl9kaXN0cyhic2VkX3VuaWZvcm1fYm9vdHN0cmFwcywgZGlzdF90eXBlID0gJ2JzZWRfYm9vdHN0cmFwcycpCgppbnZpc2libGUoYnNlZF91bmlmb3JtX2Jvb3RzdHJhcF9wbG90KQpgYGAKCiMjIyBDb21wYXJlIEJTRURzIGFtb25nIGNvbW11bml0aWVzCgojIyMjIEVybmVzdCBhcHByb2FjaAotIEZvciBldmVyeSBwYWlyIG9mIGNvbW11bml0aWVzLCBjcmVhdGUgYSBwb29sIG9mIG1hc3NlcyBvZiBhbGwgaW5kaXZpZHVhbHMgZnJvbSBib3RoIGNvbW11bml0aWVzLgotIERyYXcgdHdvIG5ldyBjb21tdW5pdGllcyB3aXRoIHRoZSBzYW1lIG51bWJlciBvZiBpbmRpdmlkdWFscyBhcyB0aGUgZW1waXJpY2FsIGNvbW11bml0aWVzLCBwdWxsaW5nIG1hc3NlcyBhdCByYW5kb20gZnJvbSB0aGUgcG9vbCwgd2l0aCByZXBsYWNlbWVudC4KLSBDYWxjdWxhdGUgdGhlIERPSSBmb3IgdGhlIEJTRURzIG9mIHRoZSB0d28gc2FtcGxlIGNvbW11bml0aWVzLgotIFJlcGVhdCAxMDAwMCBmb3IgZWFjaCBwYWlyLgotIFRoZSBQIHZhbHVlIGlzIHRoZSBwcm9wb3J0aW9uIG9mIHNhbXBsZSBET0lzIGdyZWF0ZXIgKGkuZS4gbGVzcyBvdmVybGFwKSB0aGFuIHRoZSBlbXBpcmljYWwgdmFsdWUuIAoKIyMjIyBUcmFuc2xhdGlvbiB0byBgcmVwbGljYXRlLWJlY3NgCi0gRm9yIGV2ZXJ5IHBhaXIgb2YgY29tbXVuaXRpZXMsIHBvb2wgYWxsIHRoZSBtYXNzZXMKLSBSZXNhbXBsZSB0d28gY29tbXVuaXRpZXMgb2YgdGhlIHJpZ2h0IHNpemVzCi0gQ29uc3RydWN0IEJTRURzIGZvciBib3RoIGNvbW11bml0aWVzCi0gQ2FsY3VsYXRlIHRoZSBET0kgb2YgdGhlIHR3byBCU0VEcwotIFJlcGVhdCAxMDAwMHgKCmBgYHtyIHBhaXJzIGZvciBjcm9zc2NvbW11bml0eSBCU0VEIGNvbXBhcmlzb25zfQpjb21tdW5pdHlfY29tYmluYXRpb25faW5kaWNlcyA9IHV0aWxzOjpjb21ibih4ID0gYygxOjkpLCBtID0gMiwgc2ltcGxpZnkgPSBUUlVFKSAlPiUKICB0KCkgJT4lCiAgYXMuZGF0YS5mcmFtZSgpICU+JQogIGRwbHlyOjpyZW5hbWUoY29tbXVuaXR5X2EgPSBWMSwgY29tbXVuaXR5X2IgPSBWMikKCmNvbWJpbmVfY29tbXVuaXRpZXMgPSBmdW5jdGlvbihpbmRpY2VzLCBjb21tdW5pdGllcykgewogIGNvbW11bml0eV9jb21iaW5hdGlvbiA9IGxpc3QoY29tbXVuaXR5X2EgPSBjb21tdW5pdGllc1tbaW5kaWNlc1sxXV1dLCBjb21tdW5pdHlfYiA9IGNvbW11bml0aWVzW1tpbmRpY2VzWzJdXV0sIGNvbW11bml0eV9uYW1lcyA9IGMobmFtZXMoY29tbXVuaXRpZXMpW1tpbmRpY2VzWzFdXV0sIG5hbWVzKGNvbW11bml0aWVzKVtbaW5kaWNlc1syXV1dKSkKICAKICByZXR1cm4oY29tbXVuaXR5X2NvbWJpbmF0aW9uKQp9Cgpjb21tdW5pdHlfY29tYmluYXRpb25zID0gYXBwbHkoY29tbXVuaXR5X2NvbWJpbmF0aW9uX2luZGljZXMsIE1BUkdJTiA9IDEsIEZVTiA9IGNvbWJpbmVfY29tbXVuaXRpZXMsIGNvbW11bml0aWVzID0gY29tbXVuaXRpZXMpCgpgYGAKCmBgYHtyIGNyb3NzIGNvbW11bml0eSBCU0VEIGNvbXBhcmlzb25zfQoKYnNlZF9jcm9zc2NvbW1fYm9vdHN0cmFwcyA9IGxhcHBseShjb21tdW5pdHlfY29tYmluYXRpb25zLCBGVU4gPSBjb21tdW5pdHlfYm9vdHN0cmFwLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBib290c3RyYXBfZnVuY3Rpb24gPSAnYm9vdHN0cmFwX2Nyb3NzY29tbV9ic2VkcycsIG5ib290c3RyYXBzID0gMTApCgoKYGBgCgpgYGB7ciBwbG90IGNyb3NzIGNvbW11bml0eSBjb21wYXJpc29ucywgZWNobyA9IEYsIGZpZy5oZWlnaHQ9MzAsIGZpZy53aWR0aD0xMH0KCmNyb3NzY29tbV9ib290c3RyYXBfcGxvdCA9IHBsb3RfY3Jvc3Njb21tX2JzZWRzKGJzZWRfY3Jvc3Njb21tX2Jvb3RzdHJhcHMpCgppbnZpc2libGUoY3Jvc3Njb21tX2Jvb3RzdHJhcF9wbG90KQoKYGBgCgpgYGB7ciBwbG90IGNyb3NzIGNvbW11bml0eSBwIHZhbHVlcywgZWNobyA9IEYsIGZpZy5oZWlnaHQgPSA1LCBmaWcud2lkdGggPSA1fQpwdmFsc19oaXN0b2dyYW0gPSBwbG90X3B2YWxzKGJzZWRfY3Jvc3Njb21tX2Jvb3RzdHJhcHMpCgpwdmFsc19oaXN0b2dyYW0KYGBgCgoKU2VlIGhpc3RvZ3JhbSBvZiBwIHZhbHVlcyBmb3IgY29tcGFyaXNvbnMgdG8gc2VlIGlmIGNvbW11aXRpZXMnIEJTRURzIGFyZSB0aGUgc2FtZSBvciBkaWZmZXJlbnQuCgojIyMgVGVzdGluZyBCU0RzIGZvciB1bmlmb3JtaXR5CgojIyMjIEVybmVzdCBhcHByb2FjaAotICRcZGVsdGEkLWNvcnJlY3RlZCBLb2xtb2dvcm92LVNtaXJub3YgdGVzdC4gCiAgLSAiVGhlICRcZGVsdGEkLWNvcnJlY3RlZCBLLVMgdGVzdCBpbmNyZWFzZXMgdGhlIHBvd2VyIG9mIHRoZSB0ZXN0IHdoZW4gc2FtcGxlIHNpemVzIGFyZSBzbWFsbCAobiA8IDI1OyBaYXIgMTk5OSkiCi0gVGhlICRcZGVsdGEkLWNvcnJlY3RlZCB0ZXN0IGlzIG5vdCB3aWRlbHkgZGlzY3Vzc2VkIG9ubGluZS4gCgojIyMjIFRyYW5zbGF0aW9uIHRvIGByZXBsaWNhdGUtYmVjc2A6CgoqRnJvbSBaYXIgKDE5OTkpIF9CaW9zdGF0aXN0aWNhbCBBbmFseXNpc18uKgoKIyMjIyMgQmFzZSBLLVMgdGVzdAotIFRha2UgdmVjdG9yIG9mIG1lYXN1cmVtZW50cyAkWF9pJC4gCi0gRm9yIGVhY2ggJFhfaSQgcmVjb3JkIHRoZSBvYnNlcnZlZCBmcmVxdWVuY3kgJGZfaSQgKG51bWJlciBvZiBvYnNlcnZhdGlvbnMgd2l0aCB0aGF0IHZhbHVlKS4KLSBEZXRlcm1pbmUgY3VtdWxhdGl2ZSBvYnNlcnZlZCBmcmVxdWVuY2llcyAkRl9pJCBhbmQgY3VtdWxhdGl2ZSByZWxhdGl2ZSBmcmVxdWVuY2llcyAkXHRleHRybXtyZWx9Rl9pJDoKICAgIC0gJFx0ZXh0cm17cmVsfUZfaSA9IFxmcmFje0ZfaX17bn0kIHdoZXJlICRuJCBpcyB0aGUgbnVtYmVyIG9mIG1lYXN1cmVtZW50cyB0YWtlbi4gCiAgICAtICRcdGV4dHJte3JlbH1GX2kkIGlzIHRoZSBwcm9wb3J0aW9uIG9mIHRoZSBzYW1wbGUgdGhhdCBpcyBtZWFzdXJlbWVudHMgJFxsZXEgWF9pJC4gCi0gRm9yIGVhY2ggJFhfaSQsIGRldGVybWluZSB0aGUgY3VtdWxhdGl2ZSAqcmVsYXRpdmUqIGV4cGVjdGVkIGZyZXF1ZW5jeSBmcm9tIHRoZSBjb21wYXJpc29uIGRpc3RyaWJ1dGlvbiwgJFx0ZXh0cm17cmVsfVxoYXR7Rl9pfSQuCiAgICAtIEZvciBhIHVuaWZvcm0gZGlzdHJpYnV0aW9uLCAkXHRleHRybXtyZWx9XGhhdHtGX2l9ID0gXGZyYWN7WF9pIC0gXG1pbihYKX17XG1heChYKSAtIFxtaW4oWCl9JAotIERldGVybWluZSAkRF9pJCBhbmQgJEQnX2kkIGFzOgogICAgLSAkRF9pID0gfHtcdGV4dHJte3JlbH1GX2kgLSBcdGV4dHJte3JlbH1caGF0e0ZfaX19fCQKICAgIC0gJEQnX2kgPSB8e1x0ZXh0cm17cmVsfUZfe2ktMX0gLSBcdGV4dHJte3JlbH1caGF0e0ZfaX19fCQKICAgICAgICAtIG5vdGUgJEZfMCA9IDAkIHNvICREJ18xID0gXHRleHRybXtyZWx9XGhhdHtGX2l9JAotIFRoZSB0ZXN0IHN0YXRpc3RpYyAkRCQgaXM6CiAgICAtICREID0gXG1heFsoXG1heChEX2kpLCAoXG1heChEJ19pKV0kCi0gQ29tcGFyZSB0byBjcml0aWNhbCB2YWx1ZXMgZnJvbSBhcHBlbmRpeC4KCiMjIyMjICRcZGVsdGEkLWNvcnJlY3RlZCBLUyB0ZXN0CgotIEZvciBzbWFsbCBzYW1wbGUgc2l6ZXMgKDwyNSkgd2UgY2FuIG9idGFpbiBpbmNyZWFzZWQgcG93ZXIgdXNpbmcgdGhlICRcZGVsdGEkLWNvcnJlY3RlZCBLUyB0ZXN0LgotIEZvciBlYWNoICRpJCBkZXRlcm1pbmUKICAgIC0gJFx0ZXh0cm17cmVsfUdfaSA9IFxmcmFje0ZfaX17biArIDF9JAogICAgLSAkXHRleHRybXtyZWx9RydfaSA9IFxmcmFje0ZfaSAtIDF9e24gLSAxfSQKLSBUaGVuIG9idGFpbiBzaW1pbGFyICREJHMKICAgIC0gJERfezAsIGl9ID0gfFx0ZXh0cm17cmVsfUdfaSAtIFx0ZXh0cm17cmVsfVxoYXR7Rl9pfXwkCiAgICAtICREX3sxLCBpfSA9IHxcdGV4dHJte3JlbH1HJ19pIC0gXHRleHRybXtyZWx9XGhhdHtGX2l9fCQKLSBUaGUgdGVzdCBzdGF0aXN0aWMgaXMgZWl0aGVyICRcbWF4KERfezAsIGl9KSQgb3IgJFxtYXgoRF97MSwgaX0pJCwgd2hpY2hldmVyIGxlYWRzIHRvIHRoZSBoaWdoZXN0IGxldmVsIG9mIHNpZ25pZmljYW5jZS9zbWFsbGVzdCBwcm9iYWJpbGl0eS4gTG9vayB1cCBzaWduaWZpY2FuY2UgaW4gdGFibGUgZnJvbSBhcHBlbmRpeC4gVGhlIDEgYW5kIDAgYXJlIHRoZSAkXGRlbHRhJHMuIAoKClRhYmxlcyBvZiBjcml0aWNhbCB2YWx1ZXMgd2VyZSBlbnRlcmVkIGJ5IGhhbmQgZnJvbSB0aGUgYXBwZW5kaXggdG8gWmFyICgxOTk5KS4gTm90ZSB0aGF0IHRoZSAkXGRlbHRhJC1jb3JyZWN0aW9uIGlzIG9ubHkgaW5jbHVkZWQgaW4gdGhlIHNldmVudGggZWRpdGlvbi4gCgpgYGB7ciBic2RzIGRlbHRha3MgdG8gdW5pZm9ybX0KCmJzZF91bmlmb3JtX2tzID0gbGFwcGx5KGJzZHMsIEZVTiA9IHphcl9rc190ZXN0LCBkZWx0YV9jb3JyZWN0aW9uID0gVCkKCmBgYAo=